﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NewsMine.DomainObjects;
using NewsMine.Storage;
using System.Xml.Serialization;
using System.IO;

namespace NewsMine.DataManagers
{
    public class ChannelManager
    {
        #region CRUD operations

        IKeyValueStore channelStore;

        public ChannelManager()
        {
            channelStore = Defaults.ChannelStore;
        }

        public void AddChannel(Channel channel)
        {
            throw new NotImplementedException(); // for now we are going to rely on the xml config stuff... just postpone this implementation.

            channelStore.Open();

            if (IsChannelNameExists(channel.Name) == true)
            {
                throw new ApplicationException("This channel is already exists.");
            }

            channelStore.Set(channel.Name, channel);

            channelStore.Close();
        }


        public void ReplaceChannel(Channel channel)
        {
            throw new NotImplementedException(); // for now we are going to rely on the xml config stuff... just postpone this implementation.

            channelStore.Open();

            channelStore.Replace(channel.Name, channel);

            channelStore.Close();
        }

        public void SaveChannel(Channel channel)
        {
            throw new NotImplementedException(); // for now we are going to rely on the xml config stuff... just postpone this implementation.

            throw new NotImplementedException();
        }

        public void DeleteChannel(Channel channel)
        {
            throw new NotImplementedException(); // for now we are going to rely on the xml config stuff... just postpone this implementation.

            DeleteChannel(channel.Name);
        }

        public void DeleteChannel(string channelName)
        {
            throw new NotImplementedException(); // for now we are going to rely on the xml config stuff... just postpone this implementation.

            channelStore.Open();

            if (IsChannelNameExists(channelName) == false)
            {
                throw new ApplicationException("This channel is not exists.");
            }

            channelStore.Delete(channelName);

            channelStore.Close();
        }


        static XmlSerializer ser = new XmlSerializer(typeof(List<Channel>));


        public static void SaveChannelsToXmlFile()
        {
            string basePath = NewsMine.Configuration.ConfigurationManager.StorageBaseFolder;

            string channelsXmlFilePath = Path.Combine(basePath, "Channels.xml");

            List<Channel> defaultChannels = ChannelManager.GetChannelsForMainMenu();

            var fs = File.OpenWrite(channelsXmlFilePath);

            ser.Serialize(fs, defaultChannels);

            fs.Close();
        }

        static DateTime xmlLastAccessedTimeStamp = DateTime.MinValue;
        static DateTime lastAccessedTime = DateTime.MinValue;

        public static bool LoadChannelsFromXmlFile()
        {
            //making sure every after 30 secs only the file mofied check will happen...
            if (channels.Count > 0 && lastAccessedTime.AddSeconds(30) < DateTime.UtcNow)
            {
                lastAccessedTime = DateTime.UtcNow;
            }

            

            string basePath = NewsMine.Configuration.ConfigurationManager.StorageBaseFolder;

            string channelsXmlFilePath = Path.Combine(basePath, "Channels.xml");

            if (File.Exists(channelsXmlFilePath))
            {
                var time = File.GetLastWriteTimeUtc(channelsXmlFilePath);

                if (time != xmlLastAccessedTimeStamp || channels.Count == 0)
                {
                    var fs1 = File.OpenRead(channelsXmlFilePath);

                    List<Channel> channelsFromFile = (List<Channel>)ser.Deserialize(fs1);

                    fs1.Close();
                    channels = channelsFromFile;

                    lastAccessedTime = DateTime.UtcNow;
                    xmlLastAccessedTimeStamp = time;
                }

                foreach (var c in channels)
                {
                    c.KeyWordList = new List<string>();
                    foreach (var categoryName in c.Name.Split('-'))
                    {
                        c.KeyWordList.AddRange(KeyWordManager.GetAllKeywordsByCategory(categoryName.ToLower()));
                    }

                    c.KeyWordList = c.KeyWordList.Distinct().ToList();
                }


                return true;
            }
            else
                return false;
        }

        public static string ValidateChannelsXmlFile()
        {
            StringBuilder sb = new StringBuilder();

            try
            {
                string basePath = NewsMine.Configuration.ConfigurationManager.StorageBaseFolder;

                string channelsXmlFilePath = Path.Combine(basePath, "Channels.xml");

                if (!File.Exists(channelsXmlFilePath))
                {
                    sb.Append("File not found at " + channelsXmlFilePath);
                }

                var fs1 = File.OpenRead(channelsXmlFilePath);

                List<Channel> channelsFromFile = (List<Channel>)ser.Deserialize(fs1);

                sb.AppendLine("channels are loaded successfully.");

                Dictionary<string, Channel> channelDictionary = new Dictionary<string, Channel>();

                foreach (Channel ch in channelsFromFile)
                {

                    if (string.IsNullOrEmpty(ch.Name))
                    {
                        sb.AppendLine(ch.Name + " : " + " Name not found");
                    }


                    if (string.IsNullOrEmpty(ch.Language))
                    {
                        sb.AppendLine(ch.Name + " : " + " Language not found");
                    }

                    if (string.IsNullOrEmpty(ch.KeyWords))
                    {
                        sb.AppendLine(ch.Name + " : " + " keywords not found");
                    }

                    if (string.IsNullOrEmpty(ch.Description))
                    {
                        sb.AppendLine(ch.Name + " : " + " Description not found");
                    }

                    if (string.IsNullOrEmpty(ch.DisplayName))
                    {
                        sb.AppendLine(ch.Name + " : " + " DisplayName not found");
                    }

                    if (string.IsNullOrEmpty(ch.Domains))
                    {
                        sb.AppendLine(ch.Name + " : " + " domains not found");
                    }

                    if (string.IsNullOrEmpty(ch.Query))
                    {
                        sb.AppendLine(ch.Name + " : " + " Query not found");
                    }


                    if (ch.Rank == 0)
                    {
                        sb.AppendLine(ch.Name + " : " + " rank not found");
                    }





                    if (channelDictionary.Keys.Contains(ch.Name.ToLower()))
                    {
                        sb.AppendLine(ch.Name + " already existed...");
                    }
                    else
                        channelDictionary.Add(ch.Name.ToLower(), ch);

                }


            }
            catch (Exception ex)
            {
                sb.Append("Error while validating xml file. " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace);
            }

            return sb.ToString();
        }


        #endregion

        #region Read Operations

        public bool IsChannelNameExists(string channelName)
        {
            if (channels.Count == 0)
            {
                GetChannelsForMainMenu();
            }

            var matchedChannelsForNameCount = (from ch in channels
                                               where ch.Name.ToLower() == channelName.ToLower()
                                               select ch).Count();

            if (matchedChannelsForNameCount > 0)
                return true;


            if (channelStore.Get(channelName) != null)
                return true;
            else
                return false;
        }

        static List<Channel> channels = new List<Channel>();



        static ChannelManager staticChannelManagerForStaticMembersToUse = new ChannelManager();

        public static Channel GetDefaultChannelForLanguage(string language)
        {
            //this will return the latest news channel which is hard coded in the below method.

            GetChannelsForMainMenu();

            var result = (from ch in channels
                          where ch.Language.ToLower() == language.ToLower()
                          && ch.IsDefault == true
                          orderby ch.Rank, ch.Name
                          select ch
                          ).FirstOrDefault();

            return result;
        }

        public static List<Channel> GetChannelsForMainMenu()
        {
            string englishtopstoriesQuery = "";
            string englishBusinessNewsQuery = "";
            string englishSportsNewsQuery = "";


            LoadChannelsFromXmlFile();


            if (channels.Count > 0)
                return channels;

            channels.Add(new Channel { Name = "telugu-news", Language = "telugu", Rank = 1, Query = "language:telugu", Description = "All latest telugu news, Andhra pradesh news", DisplayName = "తాజా వార్తలు", IsDefault = true });
            channels.Add(new Channel { Name = "telugu-business-news", Language = "telugu", KeyWords = "regional", Rank = 2, Query = "language:telugu AND link:business sensex market ipo", Description = "All latest telugu news, Andhra pradesh news", DisplayName = "బిజినెస్" });
            channels.Add(new Channel { Name = "telugu-business-news", Language = "telugu", KeyWords = "business", Rank = 2, Query = "language:telugu AND link:business sensex market ipo", Description = "All national telugu news, Andhra pradesh news", DisplayName = "జాతీయ వార్తలు" });
            channels.Add(new Channel { Name = "telugu-business-news", Language = "telugu", KeyWords = "business", Rank = 2, Query = "language:telugu AND link:business sensex market ipo", Description = "All latest telugu news, Andhra pradesh news", DisplayName = "క్రీడా వార్తలు" });
            channels.Add(new Channel { Name = "telugu-business-news", Language = "telugu", KeyWords = "business", Rank = 2, Query = "language:telugu AND link:business sensex market ipo", Description = "All latest telugu news, Andhra pradesh news", DisplayName = "సినిమా వార్తలు" });
            channels.Add(new Channel { Name = "telugu-business-news", Language = "telugu", KeyWords = "business", Rank = 2, Query = "language:telugu AND link:business sensex market ipo", Description = "All latest telugu news, Andhra pradesh news", DisplayName = "రాష్ట్ర వార్తలు" });
            channels.Add(new Channel { Name = "telugu-business-news", Language = "telugu", KeyWords = "business", Rank = 2, Query = "language:telugu AND link:business sensex market ipo", Description = "All latest telugu news, Andhra pradesh news", DisplayName = "అంతర్జాతీయం వార్తలు" });

            channels.Add(new Channel { Name = "hindi-news", Language = "hindi", Rank = 1, Query = "language:hindi", Description = "All latest hindi news", DisplayName = "ताजा खबर", IsDefault = true });

            channels.Add(new Channel { Name = "kannada-news", Language = "kannada", Rank = 1, Query = "language:kannada", Description = "All latest kannada news, Karnataka news", DisplayName = "ತಾಜಾ ಸುದ್ದಿ", IsDefault = true });

            channels.Add(new Channel { Name = "tamil-news", Language = "tamil", Rank = 1, Query = "language:tamil", Description = "All latest tamil news, Tamilnadu news", DisplayName = "புதிய செய்தி", IsDefault = true });

            channels.Add(new Channel { Name = "malayalam-news", Language = "malayalam", Rank = 1, Query = "language:malayalam", Description = "All latest malayalam news, kerala news", DisplayName = "Latest News", IsDefault = true });

            channels.Add(new Channel { Name = "english-news", Language = "english", Rank = 1, Query = "language:english", Description = "All latest english news, all india news", DisplayName = "Latest News", IsDefault = true });

            channels.Add(new Channel { Name = "gujarati-news", Language = "gujarati", Rank = 1, Query = "language:gujarati", Description = "All latest gujarati news, Gujarath news", DisplayName = "તાજા સમાચાર", IsDefault = true });

            //channels.Add(new Channel { Name = "marati-news", Language = "marathi", Rank = 1, Query = "language:marathi", Description = "All latest marathi news, Maharashtra marati news", DisplayName = "मराठी ताज्या बातम्या" });
            channels.Add(new Channel { Name = "marathi-news", Language = "marathi", Rank = 1, Query = "language:marathi", Description = "All latest marathi news, Maharashtra marati news", DisplayName = "मराठी ताज्या बातम्या", IsDefault = true });

            channels.Add(new Channel { Name = "bengali-news", Language = "bengali", Rank = 1, Query = "language:bengali", Description = "All latest bengali news", DisplayName = "তাজা খবর", IsDefault = true });


            channels = (from c in channels
                        orderby c.Rank, c.Name
                        select c).ToList<Channel>();

            return channels;
        }


        public List<Channel> GetAllChannels()
        {

            channelStore.Open();

            int count = channelStore.GetCount();

            var channelObjects = channelStore.Get(0, count + 1);

            var channels = new List<Channel>();

            foreach (var channelObject in channelObjects)
            {
                Channel channel = (Channel)channelObject;
                channels.Add(channel);
            }

            channelStore.Close();

            return channels;
        }

        public Channel GetChennelByName(string name)
        {

            GetChannelsForMainMenu();


            var matchedChannelsFromMenuListChannels = (from ch in channels
                                                       where ch.Name.ToLower() == name.ToLower()
                                                       select ch).FirstOrDefault();


            return matchedChannelsFromMenuListChannels;




            channelStore.Open();

            if (IsChannelNameExists(name) == false)
            {
                return null;
            }

            object obj = channelStore.Get(name);

            channelStore.Close();

            if (obj.GetType() == typeof(Channel))
            {
                return (Channel)obj;
            }
            else
                return null;
        }

        public List<Channel> GetChannelsByLanguage(string language)
        {
            throw new NotImplementedException();
        }

        public List<Channel> GetChannelsByTags(string commaSeperatedTagsList)
        {
            throw new NotImplementedException();
        }

        public List<Channel> GetChannelsBySearch(string searchCriteria)
        {
            throw new NotImplementedException();
        }

        public List<Channel> GetRelavantChannels(Channel channel)
        {
            throw new NotImplementedException();
        }

        #endregion




        static Dictionary<string, string> dictChannelQueries = new Dictionary<string, string>();

        public static string GetQuery(Channel channel)
        {

            if (dictChannelQueries.ContainsKey(channel.Name.ToLower()))
            {
                return dictChannelQueries[channel.Name.ToLower()];
            }

            string preparedQuery = null;


          
            bool isCategoryByATag = true;

            //if (NewsMine.Configuration.ConfigurationManager.Get("isCategoryByATag") != null)
            //{
            //    isCategoryByATag = Convert.ToBoolean(NewsMine.Configuration.ConfigurationManager.Get("isCategoryByATag"));
            //}



            //if (isCategoryByATag)
            if (true)
            {
                var keyWordsInName = channel.Name.Split('-').ToList();

                keyWordsInName = keyWordsInName.Where(k => !string.IsNullOrEmpty(k)).Distinct().ToList();

                string tagBaseQuery = keyWordsInName.Count > 0 ? "atag:" + String.Join(" OR atag:", keyWordsInName) : "abc:abc";

                string channelQuery = (!string.IsNullOrEmpty(channel.Query)) ? channel.Query : "abc:abc";

                string languageQuery = (!string.IsNullOrEmpty(channel.Language)) ? "language:" + channel.Language.ToLower() : "abc:abc";


                preparedQuery = "( (" + channelQuery + ") OR (" + tagBaseQuery + ") ) AND (" + languageQuery + ")";

            }
            else
            {
                //var keyWordsInName = channel.Name.Split('-').ToList();

                //keyWordsInName = keyWordsInName.Where(k => !string.IsNullOrEmpty(k)).Distinct().ToList();

                //string tagBaseQuery = keyWordsInName.Count > 0 ? "atag:" + String.Join(" OR atag:", keyWordsInName) : "abc:abc";

                //string channelQuery = (!string.IsNullOrEmpty(channel.Query)) ? channel.Query : "abc:abc";

                //string languageQuery = (!string.IsNullOrEmpty(channel.Language)) ? "language:" + channel.Language.ToLower() : "abc:abc";


                //preparedQuery = "( (" + channelQuery + ") OR (" + tagBaseQuery + ") ) AND (" + languageQuery + ")";
            }


            dictChannelQueries.Add(channel.Name.ToLower(), preparedQuery);

            return preparedQuery;
        }

    }
}
